home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
kernel
/
proc
/
procTable.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-18
|
17KB
|
674 lines
/*
* procTable.c --
*
* Routines to manage the process table. This maintains a monitor
* that synchronizes access to PCB's.
*
* Copyright 1985, 1988 Regents of the University of California
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#ifndef lint
static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/proc/procTable.c,v 9.16 92/01/06 15:03:44 kupfer Exp $ SPRITE (Berkeley)";
#endif not lint
#include <sprite.h>
#include <mach.h>
#include <proc.h>
#include <procInt.h>
#include <sync.h>
#include <sched.h>
#include <timer.h>
#include <list.h>
#include <vm.h>
#include <sys.h>
#include <stdlib.h>
#include <rpc.h>
static Sync_Lock tableLock;
#define LOCKPTR &tableLock
static Proc_ControlBlock *RunningProcesses[MACH_MAX_NUM_PROCESSORS];
Proc_ControlBlock **proc_RunningProcesses = RunningProcesses;
Proc_ControlBlock **proc_PCBTable;
#define PROC_MAX_PROCESSES 256
#define PROC_PCB_NUM_ALLOC 16
int proc_MaxNumProcesses;
int procLastSlot = 0; /* Circular index into proctable for choosing slots */
static int realMaxProcesses; /* The absolute number of process table
* entries, not necessarily allocated yet. */
static int entriesInUse = 0; /* Number of PCB's in use. */
static void InitPCB _ARGS_((Proc_ControlBlock *pcbPtr, int i));
static void AddPCBs _ARGS_((Proc_ControlBlock **procPtrPtr));
/*
* ----------------------------------------------------------------------------
*
* ProcInitTable --
*
* Initializes the PCB table and running process table. Must be called
* at initialization time with interrupts off. Initializes an array
* of PROC_MAX_PROCESSES pointers to PCB's but only allocates
* PROC_PCB_NUM_ALLOC entries at first. The rest are done dynamically.
*
* Results:
* None.
*
* Side effects:
* The PCB table is initialized.
*
* ----------------------------------------------------------------------------
*/
void
ProcInitTable()
{
register int i;
register Proc_ControlBlock *pcbPtr;
int maxRunningProcesses;
maxRunningProcesses = MACH_MAX_NUM_PROCESSORS;
proc_MaxNumProcesses = PROC_PCB_NUM_ALLOC;
realMaxProcesses = PROC_MAX_PROCESSES;
proc_PCBTable = (Proc_ControlBlock **)
Vm_BootAlloc(realMaxProcesses * sizeof(pcbPtr));
for (i = 0; i < proc_MaxNumProcesses; i++) {
pcbPtr = (Proc_ControlBlock *) Vm_BootAlloc(sizeof(Proc_ControlBlock));
proc_PCBTable[i] = pcbPtr;
InitPCB(pcbPtr, i);
}
/*
* Set the rest of the proc table to catch any misuse of nonexistent
* entries.
*/
for (i = proc_MaxNumProcesses; i < realMaxProcesses; i++) {
proc_PCBTable[i] = (Proc_ControlBlock *) NIL;
}
for (i = 0; i < maxRunningProcesses; i++) {
proc_RunningProcesses[i] = (Proc_ControlBlock *) NIL;
}
Sync_LockInitDynamic(&tableLock, "Proc:tableLock");
}
/*
* ----------------------------------------------------------------------------
*
* InitPCB --
*
* Initializes a process control block.
*
* Results:
* None.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
static void
InitPCB(pcbPtr, i)
Proc_ControlBlock *pcbPtr;
int i;
{
List_InitElement((List_Links *)pcbPtr);
pcbPtr->state = PROC_UNUSED;
pcbPtr->processID = i;
pcbPtr->genFlags = 0;
/*
* Initialize the pointers to the list headers and the
* PCB entry. These values do not change when the PCB
* entry is re-used.
*/
pcbPtr->childList = &(pcbPtr->childListHdr);
pcbPtr->siblingElement.procPtr = pcbPtr;
pcbPtr->familyElement.procPtr = pcbPtr;
/*
* Set the links to NIL to catch any invalid uses of
* the lists before they are properly initialized.
* These pointers change whenever the PCB entry is re-used.
*/
pcbPtr->childListHdr.nextPtr = (List_Links *) NIL;
pcbPtr->childListHdr.prevPtr = (List_Links *) NIL;
List_InitElement((List_Links *)&pcbPtr->siblingElement);
List_InitElement((List_Links *)&pcbPtr->familyElement);
pcbPtr->eventHashChain.procPtr = pcbPtr;
List_InitElement((List_Links *)&pcbPtr->eventHashChain);
pcbPtr->event = NIL;
pcbPtr->peerHostID = NIL;
pcbPtr->peerProcessID = (Proc_PID) NIL;
pcbPtr->remoteExecBuffer = (Address) NIL;
pcbPtr->migCmdBuffer = (Address) NIL;
pcbPtr->migCmdBufSize = 0;
pcbPtr->migFlags = 0;
pcbPtr->argString = (char *) NIL;
#ifdef LOCKDEP
pcbPtr->lockStackSize = 0;
#endif
pcbPtr->vmPtr = (Vm_ProcInfo *)NIL;
pcbPtr->fsPtr = (Fs_ProcessState *)NIL;
pcbPtr->rpcClientProcess = (Proc_ControlBlock *) NIL;
pcbPtr->waitToken = 0;
pcbPtr->timerArray = (struct ProcIntTimerInfo *) NIL;
pcbPtr->kcallTable = mach_NormalHandlers;
pcbPtr->specialHandling = 0;
pcbPtr->machStatePtr = (struct Mach_State *)NIL;
#ifndef CLEAN_LOCK
Sync_SemInitDynamic(&pcbPtr->lockInfo, "Proc:perPCBlock");
#endif
#ifdef LOCKREG
Sync_LockRegister(&pcbPtr->lockInfo);
#endif
}
/*
* ----------------------------------------------------------------------------
*
* AddPCBs --
*
* Add new proc_ControlBlocks with sched_Mutex locked. This avoids
* conflicts accessing the proc_MaxNumProcesses variable, such as in
* the Sched_ForgetUsage routine.
*
* Results:
* None.
*
* Side effects:
* The global array of process control blocks is updated to point
* to the PCB's pointed to by procPtrPtr, and the count of useable entries
* is updated.
*
* ----------------------------------------------------------------------------
*/
static void
AddPCBs(procPtrPtr)
Proc_ControlBlock **procPtrPtr;
{
register int i;
/*
* Gain exclusive access to the process table.
*/
MASTER_LOCK(sched_MutexPtr);
for (i = 0; i < PROC_PCB_NUM_ALLOC; i++) {
proc_PCBTable[proc_MaxNumProcesses] = *procPtrPtr;
procPtrPtr++;
proc_MaxNumProcesses++;
}
MASTER_UNLOCK(sched_MutexPtr);
}
/*
* ----------------------------------------------------------------------------
*
* Proc_InitMainProc --
*
* Finish initializing the process table by making a proc table entry
* for the main process. Called with interrupts disabled.
*
* Results:
* None.
*
* Side effects:
* The first element of the proc table is modified, and the count of
* used entries is set to 1.
*
* ----------------------------------------------------------------------------
*/
void
Proc_InitMainProc()
{
register Proc_ControlBlock *procPtr;
#define MAIN_PID 0
entriesInUse = 1;
procPtr = proc_PCBTable[MAIN_PID];
/*
* Initialize the main process.
*/
procPtr->state = PROC_RUNNING;
procPtr->genFlags = PROC_KERNEL;
procPtr->syncFlags = 0;
procPtr->schedFlags = 0;
procPtr->processID = MAIN_PID | (1 << PROC_GEN_NUM_SHIFT) |
(rpc_SpriteID << PROC_ID_NUM_SHIFT);
procPtr->parentID = procPtr->processID;
procPtr->billingRate = PROC_NORMAL_PRIORITY;
procPtr->recentUsage = 0;
procPtr->weightedUsage = 0;
procPtr->unweightedUsage = 0;
procPtr->kernelCpuUsage.ticks = timer_TicksZeroSeconds;
procPtr->userCpuUsage.ticks = timer_TicksZeroSeconds;
procPtr->childKernelCpuUsage.ticks = timer_TicksZeroSeconds;
procPtr->childUserCpuUsage.ticks = timer_TicksZeroSeconds;
procPtr->numQuantumEnds = 0;
procPtr->numWaitEvents = 0;
procPtr->Prof_Buffer = (short *) NIL;
procPtr->Prof_BufferSize = 0;
procPtr->Prof_Offset = 0;
procPtr->Prof_Scale = 0;
procPtr->Prof_PC = 0;
Mach_InitFirstProc(procPtr);
Vm_ProcInit(procPtr);
(void) VmMach_SetupContext(procPtr);
procPtr->familyID = PROC_NO_FAMILY; /* not in a family */
List_Init(procPtr->childList);
procPtr->userID = 0;
procPtr->effectiveUserID = 0;
Sig_ProcInit(procPtr);
procPtr->processor = Mach_GetProcessorNumber();
Proc_SetCurrentProc(procPtr);
ProcInitMainEnviron(procPtr);
ProcFamilyHashInit();
procPtr->peerProcessID = (Proc_PID) NIL;
procPtr->peerHostID = (int) NIL;
procPtr->remoteExecBuffer = (Address) NIL;
}
/*
* ----------------------------------------------------------------------------
*
* Proc_LockPID --
*
* Determine the validity of the given pid and if valid return a pointer
* to the proc table entry. The proc table entry is returned locked.
*
* Results:
* Pointer to proc table entry.
*
* Side effects:
* Proc table entry is locked.
*
* ----------------------------------------------------------------------------
*/
ENTRY Proc_ControlBlock *
Proc_LockPID(pid)
Proc_PID pid;
{
register Proc_ControlBlock *procPtr;
#ifndef CLEAN_LOCK
register Sync_Semaphore *lockPtr;
#endif
LOCK_MONITOR;
if (Proc_PIDToIndex(pid) >= proc_MaxNumProcesses) {
UNLOCK_MONITOR;
return((Proc_ControlBlock *) NIL);
}
procPtr = proc_PCBTable[Proc_PIDToIndex(pid)];
#ifndef CLEAN_LOCK
lockPtr = &(procPtr->lockInfo);
#endif
while (TRUE) {
if (procPtr->state == PROC_UNUSED || procPtr->state == PROC_DEAD) {
procPtr = (Proc_ControlBlock *) NIL;
break;
}
if (procPtr->genFlags & PROC_LOCKED) {
do {
Sync_RecordMiss(lockPtr);
(void) Sync_Wait(&procPtr->lockedCondition, FALSE);
} while (procPtr->genFlags & PROC_LOCKED);
} else {
if (!Proc_ComparePIDs(procPtr->processID, pid)) {
procPtr = (Proc_ControlBlock *) NIL;
} else {
procPtr->genFlags |= PROC_LOCKED;
Sync_RecordHit(lockPtr);
Sync_StoreDbgInfo(lockPtr, FALSE);
Sync_AddPrior(lockPtr);
}
break;
}
}
UNLOCK_MONITOR;
return(procPtr);
}
/*
* ----------------------------------------------------------------------------
*
* Proc_Lock --
*
* Lock the proc table entry.
*
* Results:
* None.
*
* Side effects:
* Proc table entry is locked.
*
* ----------------------------------------------------------------------------
*/
ENTRY void
Proc_Lock(procPtr)
register Proc_ControlBlock *procPtr;
{
#ifndef CLEAN_LOCK
register Sync_Semaphore *lockPtr;
#endif
LOCK_MONITOR;
#ifndef CLEAN_LOCK
lockPtr = &(procPtr->lockInfo);
#endif
while (procPtr->genFlags & PROC_LOCKED) {
Sync_RecordMiss(lockPtr);
(void) Sync_Wait(&procPtr->lockedCondition, FALSE);
}
procPtr->genFlags |= PROC_LOCKED;
Sync_RecordHit(lockPtr);
Sync_StoreDbgInfo(lockPtr, FALSE);
Sync_AddPrior(lockPtr);
UNLOCK_MONITOR;
}
/*
* ----------------------------------------------------------------------------
*
* Proc_Unlock --
*
* Unlock the proc table entry.
*
* Results:
* None.
*
* Side effects:
* Proc table entry is unlocked.
*
* ----------------------------------------------------------------------------
*/
ENTRY void
Proc_Unlock(procPtr)
register Proc_ControlBlock *procPtr;
{
LOCK_MONITOR;
if (!(procPtr->genFlags & PROC_LOCKED)) {
panic("Proc_Unlock: PCB not locked.\n");
}
procPtr->genFlags &= ~PROC_LOCKED;
Sync_Broadcast(&procPtr->lockedCondition);
UNLOCK_MONITOR;
}
/*
*----------------------------------------------------------------------
*
* Proc_UnlockAndSwitch --
*
* Unlock a PCB and perform a context switch to the given state.
* This is done atomically: no other process can lock the PCB before
* this process context switches.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
Proc_UnlockAndSwitch(procPtr, state)
Proc_ControlBlock *procPtr; /* the PCB to unlock */
Proc_State state; /* the state to context switch to */
{
LOCK_MONITOR;
if (!(procPtr->genFlags & PROC_LOCKED)) {
panic("Proc_Unlock: PCB not locked.\n");
}
procPtr->genFlags &= ~PROC_LOCKED;
Sync_Broadcast(&procPtr->lockedCondition);
Sync_UnlockAndSwitch(LOCKPTR, state);
}
/*
* ----------------------------------------------------------------------------
*
* ProcGetUnusedPCB --
*
* Return the first unused PCB.
*
* Results:
* Pointer to PCB.
*
* Side effects:
* Proc table entry is locked and marked as PROC_NEW.
*
* ----------------------------------------------------------------------------
*/
ENTRY Proc_ControlBlock *
ProcGetUnusedPCB()
{
register Proc_ControlBlock **procPtrPtr;
register Proc_ControlBlock *procPtr;
Proc_ControlBlock *pcbArray[PROC_PCB_NUM_ALLOC];
register int i;
int generation;
LOCK_MONITOR;
/*
* See if we need to allocate more process table entries.
*/
if (entriesInUse == proc_MaxNumProcesses) {
if (proc_MaxNumProcesses > realMaxProcesses - PROC_PCB_NUM_ALLOC) {
panic("ProcGetUnusedPCB: PCB table full!!\n");
}
for (i = 0; i < PROC_PCB_NUM_ALLOC; i++) {
pcbArray[i] = (Proc_ControlBlock *)
Vm_RawAlloc(sizeof(Proc_ControlBlock));
InitPCB(pcbArray[i], proc_MaxNumProcesses + i);
}
AddPCBs(pcbArray);
}
/*
* Scan the proc table looking for an unused slot. The search is
* circular, starting just after the last slot chosen. This is done
* so that slots are not re-used often so the generation number of
* each slot can just be a few bits wide.
*/
for (i = procLastSlot, procPtrPtr = &proc_PCBTable[procLastSlot]; ; ) {
if ((*procPtrPtr)->state == PROC_UNUSED) {
break;
}
i++;
procPtrPtr++;
if (i >= proc_MaxNumProcesses) {
i = 0;
procPtrPtr = &proc_PCBTable[0];
}
/*
* Shouldn't hit this, but check to avoid infinite loop.
*/
if (i == procLastSlot) {
panic("ProcGetUnusedPCB: PCB table full!!\n");
}
}
procLastSlot = i+1;
if (procLastSlot >= proc_MaxNumProcesses) {
procLastSlot = 0;
}
procPtr = *procPtrPtr;
procPtr->genFlags = PROC_LOCKED;
procPtr->migFlags = 0;
procPtr->state = PROC_NEW;
/*
* The PCB entry has a generation number that is incremented each time
* the entry is re-used. The low-order bits are in index into
* the PCB table.
*/
generation = (procPtr->processID & PROC_GEN_NUM_MASK) >> PROC_GEN_NUM_SHIFT;
generation += 1;
generation = (generation << PROC_GEN_NUM_SHIFT) & PROC_GEN_NUM_MASK;
procPtr->processID = i | generation | (rpc_SpriteID << PROC_ID_NUM_SHIFT);
entriesInUse++;
UNLOCK_MONITOR;
return(procPtr);
}
/*
* ----------------------------------------------------------------------------
*
* ProcFreePCB --
*
* Mark the given PCB as unused.
*
* Results:
* None.
*
* Side effects:
* Proc table entry marked as PROC_UNUSED.
*
* ----------------------------------------------------------------------------
*/
ENTRY void
ProcFreePCB(procPtr)
register Proc_ControlBlock *procPtr;
{
#ifdef LOCKREG
register Sync_Semaphore *lockPtr;
#endif
LOCK_MONITOR;
#ifdef LOCKREG
lockPtr = &(procPtr->lockInfo);
#endif
while (procPtr->genFlags & PROC_LOCKED) {
#ifdef LOCKREG
Sync_RecordMiss(lockPtr);
#endif
(void) Sync_Wait(&procPtr->lockedCondition, FALSE);
}
procPtr->state = PROC_UNUSED;
procPtr->genFlags = 0;
entriesInUse--;
#ifdef LOCKREG
Sync_RecordHit(lockPtr);
#endif
UNLOCK_MONITOR;
}
/*
* ----------------------------------------------------------------------------
*
* ProcTableMatch --
*
* Go through the process table and return an array of process
* IDs for which the specified function returns TRUE.
*
* Results:
* The array of PIDs and the number of matches are returned.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
ENTRY int
ProcTableMatch(maxPids, booleanFuncPtr, pidArray)
int maxPids; /* size of pidArray */
Boolean (*booleanFuncPtr) _ARGS_((Proc_ControlBlock *pcbPtr));
/* function to match */
Proc_PID *pidArray; /* array to store results */
{
Proc_ControlBlock *pcbPtr;
int i;
int matched = 0;
LOCK_MONITOR;
for (i = 0; i < proc_MaxNumProcesses && matched < maxPids; i++) {
pcbPtr = proc_PCBTable[i];
if (pcbPtr->state == PROC_UNUSED) {
continue;
}
if ((*booleanFuncPtr)(pcbPtr)) {
pidArray[matched] = pcbPtr->processID;
matched++;
}
}
UNLOCK_MONITOR;
return(matched);
}